﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Resources;
using mogco.Properties;

namespace mogco
{
    // Контрол для отображения картинок
    // Использует список с путями к файлам в качестве источника
    public partial class PictList : UserControl, IDisposable
    {

        #region Properties
        public enum EViewMode
        {
            Vertical,
            Horizontal
        }
        private EViewMode viewMode = EViewMode.Vertical;
        /// <summary>
        /// Gets or Sets ViewMode
        /// </summary>
        [DisplayName("View Mode"),
        Category("Custom category"),
        Description("Set type of mapping")]
        public EViewMode ViewMode
        {
            get { return this.viewMode; }
            set { this.viewMode = value; }
        }
        #endregion

        ScrollBar currentScrollBar;
        protected ScrollBar CurrentScrollBar
        {
            get { return currentScrollBar; }
            set { currentScrollBar = value; }
        }

        # region events
        //public delegate void 
        public delegate void PLVScrollEventHandler(object sender, ScrollEventArgs e);
        public delegate void SelectedPictureChangedHandler(object sender, SelectedPictureChangedArgs e);
        /// <summary>
        /// Активируется в случае изменения изображения, на которое указывает мышь
        /// </summary>
        public event SelectedPictureChangedHandler SelectedPictureChanged;

        int SlotWidth = 110;
        int SlotHeight = 155;
        byte PicturesInRow    = 0;
        byte PicturesInColumn = 0;
        #endregion

        /// <summary>
        /// Список путей отображаемых изображений
        /// </summary>
        private List<string> FPictures;
        private Image[] thumbs;
        /// <summary>
        /// Буфер изображений при отображении с ОЗУ
        /// </summary>
        //List<Image> Images;

        private bool[] visibles;
        /// <summary>
        /// Указатель на текущий первый элемент
        /// </summary>
        int PointerInList;
        int Cols = 2;
        int Rows = 2;

        private delegate void SetPictureDelegate(int i, Image thumb, bool visible);
        private Thread t_getPictures;
        private Object locker_object = new Object();

        //Controls
        List<PictureBox> pictureBoxes;
        Label noImageLabel;

        int PrevSelectedPictureBox;

        public PictList()
        {
            InitializeComponent();
            //Images = new List<Image>();
            PicturesInRow = (byte) (this.Width / SlotWidth); //     calculate pictures in row
            PicturesInColumn = (byte) (this.Height / SlotHeight);// calculate pictures in column
            this.MouseWheel += new MouseEventHandler(PictList_MouseWheel);
            pictureBoxes = new List<PictureBox>();
            FPictures = new List<string>();
            noImageLabel = new Label() { Visible = false };
            this.Controls.Add(noImageLabel);
        }

        public bool AddSlots()
        {
            int left = 20; 
            int top = 10;
            vScrollBar1.Scroll += new ScrollEventHandler(currentScrollBar_Scroll);

            for(byte i = 0; i < PicturesInRow; i++)
                for (byte j = 0; j < PicturesInColumn; j++)
                {
                    pictureBoxes.Add(new PictureBox()
                    {
                        Top = top,
                        Left = left,
                        Width = SlotWidth,
                        Height = SlotHeight,
                        Visible = true,
                        SizeMode = PictureBoxSizeMode.CenterImage,
                        BorderStyle = BorderStyle.FixedSingle
                    });
                    pictureBoxes.Last().MouseHover += new EventHandler(pictureBox_MouseHover);
                    if ((j + 1) % 2 == 0)
                    {
                        top += SlotHeight + 10;
                        left = 20;
                    }
                    else
                        left += SlotWidth + 10;
                    this.Controls.Add(pictureBoxes.Last());
                }
            thumbs = new Image[Cols*Rows];
            visibles = new bool[Cols * Rows];
            return true;
        }

        public bool AddFiles(List<string> _FPictures)
        {
            noImageLabel.Visible = false;
            FPictures = _FPictures;
            if (pictureBoxes.Count == 0)
                throw new Exception("Have no slots");
            if (FPictures.Count != 0)
            {
                vScrollBar1.Maximum = FPictures.Count;
                vScrollBar1.LargeChange = 4;
                vScrollBar1.SmallChange = 2;
                vScrollBar1.Visible = true;

                try
                {
                    t_getPictures = new Thread(UpdateImagesFromFile);
                    t_getPictures.Start();
                }
                catch (Exception e)
                {
                    Logger.txtLogger.WriteMessage("Error: " + e.ToString());
                    return false;
                }
                return true;
            }
            else
                return false;
        }

        //public bool AddFiles(List<Image> images)
        //{
        //    if (pictureBoxes.Count == 0)
        //        throw new Exception("Have no slots");
        //    Images = images;
        //    if (Images.Count != 0)
        //    {
        //        vScrollBar1.Maximum = Images.Count;
        //        vScrollBar1.LargeChange = 2*Cols;
        //        vScrollBar1.SmallChange = Cols;
        //        vScrollBar1.Visible = true;
        //        try
        //        {
        //            this.UpdateImagesFromMemory();
        //        }
        //        catch (Exception e)
        //        {
        //            return false;
        //        }
        //        return true;
        //    }
        //    else
        //        return false;
        //}

        public void ChangeSize(int x, int y)
        {
        }


        public void SetNoImages()
        {
            noImageLabel.Location = new Point(this.Width / 2 - 8, this.Height / 2 - 4);
            noImageLabel.Text = "No images";
            noImageLabel.Visible = true;
            this.Invalidate();
        }

        public bool Clear()
        {
            try
            {
                foreach (PictureBox pbox in pictureBoxes)
                {
                    pbox.Image = null;
                }
                vScrollBar1.Visible = false;
                PointerInList = 0;
                SetNoImages();
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }

        private bool UpdatePB(int i, Image pict, bool visible_flag)
        {
            pictureBoxes[i].Image.Dispose();
            pictureBoxes[i].Image = pict;
            pictureBoxes[i].Visible = visible_flag;
            return true;
        }

        public bool AddFileList(List<string> files)
        {
            return true;
        }

        // events zone
        public void currentScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            if (!((Control.MouseButtons & MouseButtons.Left) == MouseButtons.Left))     // проверить, отпущена ли левая кнопка мыши
            {
                if (Math.Abs(e.NewValue - PointerInList) >= 2)
                {
                    PointerInList = e.NewValue;
                    if (FPictures.Count != 0)
                    {
                        if (t_getPictures != null)
                            if (t_getPictures.ThreadState == ThreadState.Running)
                            {
                                t_getPictures.Abort();
                                t_getPictures = null;
                            }
                        t_getPictures = new Thread(UpdateImagesFromFile);
                        t_getPictures.Start();
                    }
                    //else if (Images.Count != 0)
                    //{
                    //    UpdateImagesFromMemory();
                    //}
                }
            }
        }

        public void PictList_MouseWheel(object sender, MouseEventArgs e)
        {
            int numberOfLinesToMove = (e.Delta / (-120))*2;
            int new_point = numberOfLinesToMove + PointerInList;
            if (new_point < FPictures.Count && new_point > -1)
            {
                PointerInList = PointerInList + numberOfLinesToMove;
                vScrollBar1.Value = new_point;
            }
            else
                return;
            if (FPictures.Count != 0)
            {
                if (t_getPictures != null)
                    if (t_getPictures.ThreadState == ThreadState.Running)
                    {
                        t_getPictures.Abort();
                        t_getPictures = null;
                    }
                t_getPictures = new Thread(UpdateImagesFromFile);
                t_getPictures.Start();
            }
        }

        private void SetPicture(int i, Image thumb, bool visible)
        {
            if (this.pictureBoxes[0].InvokeRequired)
            {
                SetPictureDelegate d = new SetPictureDelegate(SetPicture);
                this.Invoke(d, i, thumb, visible);
            }
            else
            {
                UpdatePB(i, thumb, visible);
            }

        }

        //private void UpdateImagesFromMemory()
        //{
        //    ImageWorker _imworker = new ImageWorker();

        //    for (int i = 0, k = PointerInList; i < Rows*Cols; i++, k++)
        //    {
        //        if (k < Images.Count)
        //        {
        //            thumbs[i] = _imworker.GetThumbnails(Images[k], new Size(100, 145));
        //            SetPicture(i, thumbs[i], true);
        //        }
        //        else
        //        {
        //            SetPicture(i, null, false);
        //        }
        //    }
        //    if (SelectedPictureChanged != null)
        //    {
        //        SelectedPictureChangedArgs  e = new SelectedPictureChangedArgs(Images[PointerInList]);
        //        if (this.InvokeRequired)
        //        {
        //            SelectedPictureChangedHandler d = new SelectedPictureChangedHandler(SelectedPictureChanged);
        //            this.Invoke(d, e);
        //        }
        //        else
        //        {
        //            SelectedPictureChanged(this, e);
        //        }
        //    }
        //}
        /// <summary>
        /// Функция подгружает файлы изображений
        /// </summary>
        private void UpdateImagesFromFile()
        {
            ImageWorker _imworker = new ImageWorker();
            foreach (PictureBox pbox in this.pictureBoxes)
            {
                pbox.Image = Resources.loading1;
                pbox.Name = "loading";   
            }

            for (int i = 0, k = PointerInList /* k - указатель на ряд 2 - количество элементов в ряду */; i < 4; i = i + 2, k = k + 2)
            {
                if (k < FPictures.Count)
                {
                    thumbs[i] = _imworker.GetThumbnails(FPictures[k], new Size(100, 145));
                    if (thumbs[i] == null)
                        thumbs[i] = Resources.loading1;
                    else
                        pictureBoxes[i].Name = ""; // reset loading status
                    visibles[i] = true;
                }
                else
                    visibles[i] = false;
                SetPicture(i, thumbs[i], visibles[i]);
                if ((k + 1) < FPictures.Count)
                {
                    thumbs[i + 1] = _imworker.GetThumbnails(FPictures[k + 1], new Size(100, 145));
                    if (thumbs[i+1] == null)
                        thumbs[i+1] = Resources.loading1;
                    else
                        pictureBoxes[i+1].Name = ""; // reset loading status
                    visibles[i + 1] = true;
                }
                else
                    visibles[i + 1] = false;
                SetPicture(i + 1, thumbs[i + 1], visibles[i + 1]);

                if (this.InvokeRequired)
                {
                    SelectedPictureChangedHandler d = new SelectedPictureChangedHandler(SelectedPictureChanged);
                    this.Invoke(d, this, new SelectedPictureChangedArgs(FPictures[PointerInList]));
                }
                else
                {
                    SelectedPictureChanged(this, new SelectedPictureChangedArgs(FPictures[PointerInList]));
                }
            }
            //Clear thumbs
            //for (int i = 0; i < 4; i++)
            //{
            //    thumbs[i].Dispose();
            //}
        }

        private void pictureBox_MouseHover(object sender, EventArgs e)
        {
            if (t_getPictures != null)
            {
                if (t_getPictures.ThreadState != ThreadState.Running)
                {
                    // вдруг не считало, ошибка какая-то, то ничего не генерирую событие
                    if (pictureBoxes[PrevSelectedPictureBox].Equals(sender) || FPictures.Count == 0)        // if picture not changed
                        return;
                    int i = 0;
                    foreach (PictureBox pictureBox in pictureBoxes)
                    {
                        if (pictureBox.Equals(sender) && pictureBox.Name != "loading")
                        {
                            PrevSelectedPictureBox = i;
                            SelectedPictureChanged(sender, new SelectedPictureChangedArgs(FPictures[PointerInList + i])); // generate event
                            this.Focus();
                        }
                        i++;
                    }
                }
            }
        }

        // Да, коряво, но, бля, запарило
        public void Dispose()
        {
            if (t_getPictures != null)
                if (t_getPictures.ThreadState != ThreadState.Running)
                {
                    t_getPictures.Abort();
                    t_getPictures = null;
                }
        }

        // Events

        public class SelectedPictureChangedArgs : EventArgs
        {
            public SelectedPictureChangedArgs(string file)
            {
                this.file = file;
            }
            public SelectedPictureChangedArgs(Image _image)
            {
                image = _image;
            }
            public string file;
            public Image image;
        }
    }
}
